package com.motong.gongdan.config.auth;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.motong.gongdan.config.mongo.MongoContext;
import com.motong.gongdan.entity.DatabaseList;
import com.motong.gongdan.entity.Factory;
import com.motong.gongdan.entity.User;
import com.motong.gongdan.service.DatabaseListService;
import com.motong.gongdan.service.FactoryService;
import com.motong.gongdan.service.UserService;
import com.motong.gongdan.util.LoginUtil;
import com.motong.gongdan.util.RedisUtil;
import com.motong.gongdan.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @Auther: FreddieFang
 * @Date: 2021/11/10 19:46
 * @Description:
 */
@Component
@Slf4j
public class JwtInterceptor implements HandlerInterceptor {
    @Resource
    UserService userService;
    //    @Resource
//    ChangeDataSourceService changeDataSourceService;
    @Resource
    FactoryService factoryService;
    @Resource
    DatabaseListService databaseListService;

    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LoginException len = new LoginException();
        len.setCode("403");
        len.setMsg("登录状态过期");
        String token = request.getHeader("Authorization");
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        if (token == null) {
            throw len;
        }
        if (method.isAnnotationPresent(UserLoginToken.class)) {
            if (!JwtConfig.validateToken(token, "admin")) {
                log.error("验证管理员账号失败");
                throw len;
            }
            UserLoginToken adminLoginToken = method.getAnnotation(UserLoginToken.class);
            if (adminLoginToken.required()) {
                String account = "";
                try {
                    account = JwtConfig.getTokenUserAccount(token, "admin");
                } catch (Exception e) {
                    log.error("获取账号失败");
                    throw len;
                }
                if (StringUtil.isBlank(account)) {
                    return false;
                }
                Integer factoryId = (Integer) RedisUtil.get("user-admin:" + account);

                if (Objects.isNull(factoryId)) {
                    LoginException le = new LoginException();
                    le.setMsg("权限不足");
                    le.setCode("8888");
                    throw le;
                }

                Factory factory = factoryService.getById(factoryId);
                User u = userService.getOne(new QueryWrapper<User>().eq("account", account).eq("factory_id", factoryId));
                if (u.getState() != 0) {
                    LoginException le = new LoginException();
                    le.setMsg("账号已停用");
                    le.setCode("7777");
                    throw le;
                }
                if ("2".equals(u.getRole())) {
                    RedisUtil.del("JWT-TOKEN-U" + u.getAccount());
                    LoginException le = new LoginException();
                    le.setMsg("权限不足");
                    le.setCode("8888");
                    throw le;
                }
                LoginUtil.setLoginAccount(account);
                LoginUtil.setLoginUserToken(token);
                LoginUtil.setLoginUserId(u.getId());
                LoginUtil.setLoginUserFactory(u.getFactoryId());
                if (u.getFactoryId() != null) {
                    if (factory != null) {
                        DatabaseList databaseList = databaseListService.getOne(new QueryWrapper<DatabaseList>().eq("factory_code", factory.getCode()));
                        if (StringUtil.isNotBlank(databaseList.getRedisUrl()) && StringUtil.isNotBlank(databaseList.getRedisPwd())
                                && databaseList.getRedisDatabase() != null && databaseList.getRedisPort() != null) {
                            Map<String, String> redisMap = new HashMap<>();
                            redisMap.put("host", databaseList.getRedisUrl());
                            redisMap.put("port", databaseList.getRedisPort().toString());
                            redisMap.put("pwd", databaseList.getRedisPwd());
                            redisMap.put("db", databaseList.getRedisDatabase().toString());
                            RedisUtil.setOther(redisMap);
                        }
                        if (StringUtil.isNotBlank(databaseList.getMongoDatabase()) && StringUtil.isNotBlank(databaseList.getMongoUrl())) {
                            MongoContext.setMongoDbFactory(databaseList.getMongoDatabase());
                        }
                    }
                }

                return true;
            }
        } else if (method.isAnnotationPresent(H5LoginToken.class)) {
            if (!JwtConfig.validateToken(token, "h5")) {
                throw len;
            }
            H5LoginToken h5LoginToken = method.getAnnotation(H5LoginToken.class);
            if (h5LoginToken.required()) {
                String account = "";
                try {
                    account = JwtConfig.getTokenUserAccount(token, "h5");
                } catch (Exception e) {
                    throw len;
                }
                if (StringUtil.isBlank(account)) {
                    return false;
                }

                Integer factoryId = (Integer) RedisUtil.get("user-h5:" + account);

                if (Objects.isNull(factoryId)) {
                    LoginException le = new LoginException();
                    le.setMsg("权限不足");
                    le.setCode("8888");
                    throw le;
                }

                Factory factory = factoryService.getById(factoryId);
                User u = userService.getOne(new QueryWrapper<User>().eq("account", account).eq("factory_id", (Integer) RedisUtil.get("user-h5:" + account)));
                if (u.getState() != 0) {
                    LoginException le = new LoginException();
                    le.setMsg("账号已停用");
                    le.setCode("7777");
                    throw le;
                }
                LoginUtil.setLoginAccount(account);
                LoginUtil.setLoginUserToken(token);
                LoginUtil.setLoginUserId(u.getId());
                LoginUtil.setLoginUserFactory(u.getFactoryId());
                if (u.getFactoryId() != null) {
                    if (factory != null) {
                        DatabaseList databaseList = databaseListService.getOne(new QueryWrapper<DatabaseList>().eq("factory_code", factory.getCode()));
                        if (StringUtil.isNotBlank(databaseList.getRedisUrl()) && StringUtil.isNotBlank(databaseList.getRedisPwd())
                                && databaseList.getRedisDatabase() != null && databaseList.getRedisPort() != null) {
                            Map<String, String> redisMap = new HashMap<>();
                            redisMap.put("host", databaseList.getRedisUrl());
                            redisMap.put("port", databaseList.getRedisPort().toString());
                            redisMap.put("pwd", databaseList.getRedisPwd());
                            redisMap.put("db", databaseList.getRedisDatabase().toString());
                            RedisUtil.setOther(redisMap);
                        }
                        if (StringUtil.isNotBlank(databaseList.getMongoDatabase()) && StringUtil.isNotBlank(databaseList.getMongoUrl())) {
                            MongoContext.setMongoDbFactory(databaseList.getMongoDatabase());
                        }
                    }
                }
                return true;
            }
        }
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        LoginUtil.removeAll();
    }
}
